'use strict';
/**
 * 9.9.2015 - This is the new starting point of the panes.js framework
 * 1. the lib files will get package into its own npm module.
 * 2. get rip of all the hard coded path, replace with config or env variables instead
 * 3. basically this will create a top level global name space, and create the controller / model instances
 * 4. Wrap the whole express module inside as well as the socket.io
 * 5. As for module, we seperate different module type into their own files, then call according to the config
 */
var _ = require('lodash'),
    model = require('./model'),
    controller = require('./controller'),
    methods = require('./methods');
/**
 * init a global name space
 * we store those inited module here and retrieve them when we need to do
 */

global.PANES_FRAMEWORK = {};

/**
 * this is the core interface that will combine the controller and model together
 * For example:

var panes = require('panesjs');

panes().controller('ControllerName' , [function()
{


}]);
 10 Sep 2015 - after thinking about the design a bit more , the above syntax is really redudant
 because each model that construct with the model.factory is going to get store in the PanesJS object
 anyway, so there is no need to call it like this to include. Just call it directly via this.models.User
 and that's it. And we don't really want to do mixin because that might create some unwanted side effects
 since Mixin is going to level the class and merge with the new class, some naming might got overwritten.

 As for the convention and private var, it could be easily solve by write it within the module.exports closure
 since it will be local to it anyway.

 One more thing is the models will get store, and controller is create just in time so the only object array will
 be models, no controller will be store, therefore there is inter-controller communication at the moment.
 Might figure something out later if that's truly useful. But I don't see a use case right now.
**/

/**
 * constructor
 * @param (object) config object
 */
var PanesJS = function(config)
{
    this.config = config;
    this.methods = methods;
    this.connectionProfile = 'default';
};

/**
 * actually create the routing, we pass those already store config back
 */
PanesJS.prototype.router = function(app)
{
    return this.methods.generateRoutes(this , app , this.config.jwt.secret);
};
/**
 * setting to store the modules
 * @param (string || array) path to the module
 * @param (mixed) data to store
 * @param (boolean) do safe checking first!
 * @return (boolean) success:true
 */
PanesJS.prototype.set = function(path , data , safe)
{
    if (safe) {
        // if there is a.b.c and only pass a or a.b that still result in true!
        var check = _.has(global.PANES_FRAMEWORK , path);
        if (check) {
            return false;
        }
    }
    global.PANES_FRAMEWORK = _.set(global.PANES_FRAMEWORK , path , data);
    return true;
};

/**
 * module getter
 * @param (string) path to the stored data
 * @return (mixed) false on not found
 */
PanesJS.prototype.get = function(path)
{
    if (_.isUndefined(path)) {
        return global.PANES_FRAMEWORK;
    }
    var value = _.get(global.PANES_FRAMEWORK , path);
    return (_.isUndefined(value)) ? false : value;
};

/**
 * @param (string) controller name
 * @param (plain object) pass the actions implementation
 * @param (boolean) optional if the user want to protect the entire controller
 */
PanesJS.prototype.controller = function(name , actions , protectAll)
{
    // we also pass the Model into the controller Models storage, so they can use it
    return new controller(this.get('app') , this.get('models') , protectAll).factory(name , actions);
    // remember we don't want to call it until we need to. This part is only preparing
    // @TODO TBC need to dig deep into the performnace and memeory issues
};

/**
 * if the user want to add a different profle they have to call it like this
 * panes.connection('redis').model(name, schema , methods);
 */
PanesJS.prototype.connection = function(profile)
{
    this.connectionProfile = profile;
    return this;
};


/**
 * the model factory methods
 * @param (string) name of the model
 * @param (object) schema definiton - note CrouchDB doesn't use that, so might need to figure out something else
 * @param (object) methods to apply to the Schema based on different driver availability
 * @param (string) (optional || default) instance of their respective database type connection name, already init in the connection.js
 */
PanesJS.prototype.model = function(name , schema , methods)
{
    var m = new model(this , this.connectionProfile).factory( name , schema , methods);
    this.set('models.' + name , m);
    return m;
};

/**
 * export it
 */
module.exports = function(config)
{
    return new PanesJS(config);
};

// -- EOF --
